#include "MainWindow.h"
#include "ui_MainWindow.h"

#include "Loader.h"
#include "ObjMesh.h"
#include "Scene.h"
#include "Object.h"
#include "Material.h"
#include "Camera.h"
#include "Light.h"
#include "RayCasting.h"
#include "SceneIO.h"


using namespace std;


MainWindow::MainWindow()
:   QMainWindow(),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    ui->objectTabWidget->hide();
    ui->lightWidget->hide();

    connect(ui->transformWidget, SIGNAL(updated()), ui->glWidget, SLOT(updateGL()));
    connect(ui->materialWidget, SIGNAL(updated()), ui->glWidget, SLOT(updateGL()));
    connect(ui->lightWidget, SIGNAL(updated()), ui->glWidget, SLOT(updateGL()));

    connect(ui->outliner, SIGNAL(updated()), ui->glWidget, SLOT(updateGL()));
    connect(ui->outliner, SIGNAL(objectSelected(Object*)), this, SLOT(selectObject(Object*)));
    connect(ui->outliner, SIGNAL(lightSelected(Light*)), this, SLOT(selectLight(Light*)));
    connect(ui->outliner, SIGNAL(noSelection()), this, SLOT(clearSelection()));

    // Local default da biblioteca de modelos
    loadLibrary("models/");

    m_scene = new Scene();
    m_scene->addLight(new Light(Point3f(0, -5, 1), Vector3f(1, 1, 1), Vector3f(1, 1, 1)));
    m_scene->setCamera(new Camera());

    ui->glWidget->setScene(m_scene);
    ui->outliner->setScene(m_scene);
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    event->accept();
}

void MainWindow::loadLibrary(const QString &lpath)
{
    Loader::setLibrary(lpath);

    QList<FurnitureDescription> infoList = Loader::getLibraryInfoList();
    for(int i=0; i<infoList.size(); ++i)
    {
        QListWidgetItem *item = new QListWidgetItem(infoList[i].name);
        item->setFlags(item->flags() | Qt::ItemIsSelectable);
        item->setIcon(QIcon(QPixmap::fromImage(infoList[i].preview)));

        switch(infoList[i].type)
        {
            case CHAIR:
            {
                item->setData(Qt::UserRole, CHAIR);
                ui->chairsListWidget->addItem(item);
                break;
            }
            case DESK:
            {
                item->setData(Qt::UserRole, DESK);
                ui->desksListWidget->addItem(item);
                break;
            }
            case GENERAL:
            {
                item->setData(Qt::UserRole, GENERAL);
                ui->generalListWidget->addItem(item);
                break;
            }
        }
    }
}

void MainWindow::on_actionRender_triggered()
{
    static struct Local
    {
        QLabel *label;

        Local(Ui::MainWindow* ui)
        {
            label = new QLabel(ui->glWidget);
            label->setContextMenuPolicy(Qt::CustomContextMenu);
            QObject::connect(label, SIGNAL(customContextMenuRequested(QPoint)), label, SLOT(hide()));
        }

    } local(ui);

    QImage image = RayCasting::render(m_scene);
    QPixmap pixmap = QPixmap::fromImage(image);

    local.label->setPixmap(pixmap);
    local.label->show();
}

void MainWindow::on_action_LoadLibrary_triggered()
{
    QString libPath = QFileDialog::getExistingDirectory(this, "Select a Library Directory", "", QFileDialog::ShowDirsOnly);
    if(!libPath.isNull())
    {
        if(!libPath.endsWith(QDir::separator()))
            libPath.append(QDir::separator());

        loadLibrary(libPath);
    }
}

void MainWindow::on_action_SaveScene_triggered()
{
    QString filePath = QFileDialog::getSaveFileName(this, "Save Scene File", "", "*.hdesigner");
    if(!filePath.isNull())
    {
        if(!filePath.endsWith(".hdesigner"))
            filePath.append(".hdesigner");

        SceneIO io(filePath.toStdString());
        io.saveScene(m_scene);
    }
}

void MainWindow::on_action_OpenScene_triggered()
{
    QString filePath = QFileDialog::getOpenFileName(this, "Select a Scene File", "", "*.hdesigner");
    if(!filePath.isNull())
    {
        SceneIO io(filePath.toStdString());
        m_scene = io.loadScene();
        m_scene->setCamera(new Camera());

        ui->outliner->setScene(m_scene);
        ui->glWidget->setScene(m_scene);
    }
}

void MainWindow::on_action_OpenBuilding_triggered()
{
    QString filePath = QFileDialog::getOpenFileName(this, "Select a Building", "", "*.obj");
    if(!filePath.isNull())
    {
        QFileInfo info(filePath);
        Object* object = Loader::loadObject(BUILDING, info.baseName());
        if(object)
        {
            m_scene->addObject(object);
            object->setName("Building");
            ui->outliner->addObject(object);
        }
    }
}

void MainWindow::onItemDoubleClicked(QListWidgetItem *item)
{
    Object* obj = Loader::loadObject((FurnitureType)item->data(Qt::UserRole).toInt(), item->text());

    Camera *cam = m_scene->getCamera();
    Ray ray = cam->traceRay(cam->height()/2, cam->width()/2);
    Point3f p = ray(3.0);
    p.z = 0.0;
    obj->getTransform().translate(Vector3f(&p.x));

    m_scene->addObject(obj);

    ui->outliner->addObject(obj);

    ui->glWidget->updateGL();
    ui->glWidget->setFocus();
}

void MainWindow::selectObject(Object *object)
{
    ui->transformWidget->setObject(object);
    ui->materialWidget->setObject(object);

    ui->objectTabWidget->show();
    ui->lightWidget->hide();
}

void MainWindow::selectLight(Light *light)
{
    ui->lightWidget->setLight(light);

    ui->lightWidget->show();
    ui->objectTabWidget->hide();
}

void MainWindow::clearSelection()
{
    ui->lightWidget->hide();
    ui->objectTabWidget->hide();
}

void MainWindow::on_action_Light_triggered()
{
    Light *light = new Light(Point3f(), Vector3f(0.5, 0.5 ,0.5), Vector3f(0.5, 0.5, 0.5));
    m_scene->addLight(light);
    ui->outliner->addLight(light);
    ui->glWidget->updateGL();
}
